package com.qiwenshare.stock.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiwenshare.fund.model.FundDayInfo;
import com.qiwenshare.fund.model.FundInfo;
import com.qiwenshare.fund.service.impl.FundDayInfoService;
import com.qiwenshare.fund.service.impl.FundInfoService;
import com.qiwenshare.stock.api.IStockDayInfoService;
import com.qiwenshare.stock.api.IStockWeekInfoService;
import com.qiwenshare.stock.domain.StockInfo;
import com.qiwenshare.stock.domain.StockDayInfo;
import com.qiwenshare.stock.domain.StockWeekInfo;
import com.qiwenshare.stock.indicator.proxy.IndicatorProxy;
import com.qiwenshare.stock.service.StockDayInfoService;
import com.qiwenshare.stock.service.StockService;
import com.qiwenshare.stock.service.StockWeekInfoService;
import com.qiwenshare.stock.util.DataUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName StockTask
 * @Description TODO
 * @Author peng.zhang
 * @Date 13:45 2023/6/8
 * @Version 1.0
 * <p>
 * 上证主板股票代码是60开头、科创板股票代码是688开头、B股代码900开头；
 * 深证主板股票代码是000开头、中小板股票代码002开头、创业板300开头、B股代码200开头；
 * B股标价不同：沪市的B股以美元计价，深市的B股以港元计价；
 **/
@Slf4j
@Component
public class StockTask implements CommandLineRunner {
    public static ThreadPoolExecutor stockExecutor = new ThreadPoolExecutor(5,
            10,
            5000L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingDeque<>(6000),
            ThreadFactoryBuilder.create().setNamePrefix("stock-executor").build());
    @Resource
    StockService stockService;
    @Resource
    IStockDayInfoService stockDayInfoService;
    @Resource
    IStockWeekInfoService stockWeekInfoService;

    @Resource
    FundInfoService fundInfoService;
    @Resource
    FundDayInfoService fundDayInfoService;

    @Override
    public void run(String... args) throws Exception {
//        this.stockInfoTask();
//        this.stockDayInfoTask();
//        this.stockWeekInfoTask();
        this.fundDayInfoTask();
    }

    /**
     * 基础数据更新
     */
    @Scheduled(cron = "0 0 7 * * *")
    public void stockInfoTask() {
        log.info("基础数据更新 task start...");
        List<StockInfo> stockBeanList = DataUtil.getStockList();
        List<StockInfo> list = stockService.list();
        Collection<StockInfo> saveList = CollectionUtil.subtract(stockBeanList, list);
        if (saveList.size() > 0) {
            stockService.saveBatch(saveList);
        }
        log.info("基础数据更新 task end...");
    }

    /**
     * 日线数据更新
     */
    @Scheduled(cron = "0 0 8 * * *")
    public void stockDayInfoTask() throws InterruptedException {
        log.info("日线数据更新 task start...");
        long start = System.currentTimeMillis();
        List<StockInfo> list = stockService.list();
        CountDownLatch latch = new CountDownLatch(list.size());
//        for (StockBean s : list) {
        for (int i = 0; i < list.size(); i++) {
            int finalI = i;
            stockExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        long start = System.currentTimeMillis();
                        List<StockDayInfo> stockDayInfoList = DataUtil.getStockDayInfoByNum(list.get(finalI).getStockNum());
                        stockDayInfoList = new IndicatorProxy().getDayIndicatorList(stockDayInfoList);
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq("stock_num", list.get(finalI).getStockNum());
                        List<StockDayInfo> pList = stockDayInfoService.list(queryWrapper);
//                        Collection<StockDayInfo> saveList = CollectionUtil.subtract(stockDayInfoList, pList);
                        Collection<StockDayInfo> saveList = new ArrayList<>();
                        for (StockDayInfo q : stockDayInfoList) {
                            boolean needSave = true;
                            //当天的不存
                            if(q.getDate().equals(DateUtil.format(new Date(),"YYYY-MM-dd"))){
                                break;
                            }
                            for (StockDayInfo p : pList) {
                                if (p.equals(q)) {
                                    if (p.getVolume() != q.getVolume()) {
                                        q.setId(p.getId());
                                        saveList.add(q);
                                    }
                                    needSave = false;
                                    break;
                                }
                            }
                            if (needSave) {
                                saveList.add(q);
                            }
                        }
                        if (saveList.size() > 0) {
                            stockDayInfoService.saveOrUpdateBatch(saveList);
                        }
                        log.info("[{}]本次处理第{}条,本次插入数据{},本次处理耗时{}", list.get(finalI).getStockNum(), finalI, saveList.size(), System.currentTimeMillis() - start);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }
        latch.await();
        log.info("日线数据更新 task end 本次耗时{}...", System.currentTimeMillis() - start);
    }

    @Scheduled(cron = "0 0 8 * * *")
    public void stockWeekInfoTask() throws InterruptedException {
        log.info("周线数据更新 task start...");
        long start = System.currentTimeMillis();
        List<StockInfo> list = stockService.list();
        CountDownLatch latch = new CountDownLatch(list.size());
        for (StockInfo s : list) {
            stockExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        long start = System.currentTimeMillis();
                        List<StockWeekInfo> stockWeekInfoList = DataUtil.getStockWeekInfoByNum(s.getStockNum());
                        stockWeekInfoList = new IndicatorProxy().getWeekIndicatorList(stockWeekInfoList);
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq("stock_num", s.getStockNum());
                        List<StockWeekInfo> pList = stockWeekInfoService.list(queryWrapper);
                        Collection<StockWeekInfo> saveList = new ArrayList<>();
                        for (StockWeekInfo q : stockWeekInfoList) {
                            boolean needSave = true;
                            //当天的不存
                            if(q.getDate().equals(DateUtil.format(new Date(),"YYYY-MM-dd"))){
                                break;
                            }
                            for (StockWeekInfo p : pList) {
                                if (p.equals(q)) {
                                    if (p.getVolume() != q.getVolume()) {
                                        q.setId(p.getId());
                                        saveList.add(q);
                                    }
                                    needSave = false;
                                    break;
                                }
                            }
                            if (needSave) {
                                saveList.add(q);
                            }
                        }
                        if (saveList.size() > 0) {
                            stockWeekInfoService.saveOrUpdateBatch(saveList);
                        }
                        log.info("[{}]本次插入数据{},本次处理耗时{}", s.getStockNum(), saveList.size(), System.currentTimeMillis() - start);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }
        latch.await();
        log.info("周线数据更新 task end 本次耗时{}...", System.currentTimeMillis() - start);
    }


    /**
     * fund日线数据更新
     */
    @Scheduled(cron = "0 0 8 * * *")
    public void fundDayInfoTask() throws InterruptedException {
        log.info("fund日线数据更新 task start...");
        long start = System.currentTimeMillis();
        List<FundInfo> list = fundInfoService.list();
        CountDownLatch latch = new CountDownLatch(list.size());
        QueryWrapper delWrapper = new QueryWrapper();
        delWrapper.eq("date",DateUtil.format(new Date(),"YYYY-MM-dd"));
        fundDayInfoService.remove(delWrapper);
        for (FundInfo s : list) {
            stockExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        long start = System.currentTimeMillis();
                        List<StockDayInfo> stockDayInfoList = DataUtil.getStockDayInfoByNum(s.getCode());
                        stockDayInfoList = new IndicatorProxy().getDayIndicatorList(stockDayInfoList);
                        List<FundDayInfo> fundDayInfoList = BeanUtil.copyToList(stockDayInfoList,FundDayInfo.class);
                        QueryWrapper queryWrapper = new QueryWrapper();
                        queryWrapper.eq("stock_num", s.getCode());
                        List<FundDayInfo> pList = fundDayInfoService.list(queryWrapper);
                        Collection<FundDayInfo> saveList = new ArrayList<>();
                        for (FundDayInfo q : fundDayInfoList) {
                            boolean needSave = true;
                            //当天的不存
//                            if(q.getDate().equals(DateUtil.format(new Date(),"YYYY-MM-dd"))){
//                                break;
//                            }
                            for (FundDayInfo p : pList) {
                                if (p.equals(q)) {
                                    if (p.getVolume() != q.getVolume()) {
                                        q.setId(p.getId());
                                        saveList.add(q);
                                    }
                                    needSave = false;
                                    break;
                                }
                            }
                            if (needSave) {
                                saveList.add(q);
                            }
                        }
                        if (saveList.size() > 0) {
                            fundDayInfoService.saveOrUpdateBatch(saveList);
                        }
                        log.info("[{}]本次插入数据{},本次处理耗时{}", s.getCode(), saveList.size(), System.currentTimeMillis() - start);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }
        latch.await();
        log.info("fund日线数据更新 task end 本次耗时{}...", System.currentTimeMillis() - start);
    }


    // 0 0 * * * * 整点执行一次.
    // */10 * * * * * 每十秒执行一次
    // 0 0 8-10 * * * 每天8点、9点和10点执行
    // 0 0 6,19 * * * 每天上午6：00和下午7:00执行。
    // 0 0/30 8-10 * * * 8-10点之间30分钟执行一次
    // 0 0 9-17 * * MON-FRI 每个工作日9-17点之间整点执行
    // 0 0 0 25 12 ? 圣诞节执行
    // 秒 分 时 天 月 星期几
}
